/* The file is saved in UTF-8 codepage.
 * Check: «Stereotype», Section mark-§, Copyright-©, Alpha-α, Beta-β, Smile-☺
 */
package cz.pecinovsky.english.lootp._134_;


import cz.pecinovsky.english.lootp._000_.Run;

import cz.pecinovsky.english.lootp.manager.CanvasManager_Envelope.CanvasManager;
import cz.pecinovsky.english.lootp.manager.Line;
import cz.pecinovsky.english.lootp.manager.Ellipse;
import cz.pecinovsky.english.lootp.manager.IMoveable;
import cz.pecinovsky.english.lootp.manager.Multishape;
import cz.pecinovsky.english.lootp.manager.Multimover;
import cz.pecinovsky.english.lootp.manager.Rectangle;
import cz.pecinovsky.english.lootp.manager.Mover;


import cz.pecinovsky.english.lootp.manager.Text;
import cz.pecinovsky.english.lootp.manager.Triangle;


import cz.pecinovsky.english.lootp._134_.Arrow_134_.        Arrow;
import cz.pecinovsky.english.lootp._134_.Car_134_.          Car;
import cz.pecinovsky.english.lootp._134_.Light_134_.        Light;
import cz.pecinovsky.english.lootp._134_.Round_135_.      Round;
import cz.pecinovsky.english.lootp._134_.Ring_134_.        Ring;
import cz.pecinovsky.english.lootp._134_.Rotable_136_.      Rotable;
import cz.pecinovsky.english.lootp._134_.RoadField_134_.    RoadField;
import cz.pecinovsky.english.lootp._134_.TrafficLight_134_. TrafficLight;


//import cz.pecinovsky.english.lootp._134_.RingTest_134_.RingTest;
////////////////////////////////////////////////////////////////////////////////
//%%+  +++++ End of ignored starting test - place for imports +++++
//%I+ >=132z -135z
//
//import cz.pecinovsky.english.lootp.canvasmanager.IMoveable;
//import cz.pecinovsky.english.lootp.canvasmanager.Mover;
//import cz.pecinovsky.english.lootp.canvasmanager.CanvasManager;
//%I-
//%I+ >=135z
//
//import cz.pecinovsky.english.lootp.canvasmanager.Line;
//import cz.pecinovsky.english.lootp.canvasmanager.Ellipse;
//import cz.pecinovsky.english.lootp.canvasmanager.IMoveable;
//import cz.pecinovsky.english.lootp.canvasmanager.Multishape;
//import cz.pecinovsky.english.lootp.canvasmanager.Multimover;
//import cz.pecinovsky.english.lootp.canvasmanager.Rectangle;
//import cz.pecinovsky.english.lootp.canvasmanager.Mover;
//import cz.pecinovsky.english.lootp.canvasmanager.CanvasManager;
//import cz.pecinovsky.english.lootp.canvasmanager.Text;
//import cz.pecinovsky.english.lootp.canvasmanager.Triangle;
//%I-

import cz.pecinovsky.english.lootp.utility.NamedColor;
import cz.pecinovsky.english.lootp.utility.IO;
import cz.pecinovsky.english.lootp.utility.Position;

//%X+ xxxxx Start of the ovejumped text with declaration of the envelope xxxxx
/*******************************************************************************
 *<pre>
 * Předchozí:   Není - toto_je_nově_definovaná_třída
 *              Ttt v projektu Ppp
 * Následující: Prozatím není
 *
 * Projekt  Ppp
 *   + Přidáno
 *   - Odebráno
 *   ~ Změněno
 *</pre>
 */
public class RingTest_134_
{    private RingTest_134_() {}   static
////////////////////////////////////////////////////////////////////////////////
//%X- ----- End of the ovejumped text with declaration of the envelope -----


/*******************************************************************************
 * Testovací třída {@code RingTest}  slouží ke komplexnímu otestování
 * třídy {@link RingTest}.
 *
 * @author Rudolf PECINOVSKÝ
 * @version 6.03.2017 — 2010-11-08
 */
public class RingTest extends junit.framework.TestCase
{
    private CanvasManager CM;
    private Ring čtverec;
    private Ring elko;



//== CONSTANT CLASS ATTRIBUTES =================================================
//== VARIABLE CLASS ATTRIBUTES =================================================
//== STATIC CONSTRUCTOR (CLASS INITIALIZER, STATIC INICITALIZING BLOCK) ========
//== CONSTANT INSTANCE ATTRIBUTES ==============================================
//== VARIABLE INSTANCE ATTRIBUTES ==============================================
//== CLASS GETTERS AND SETTERS =================================================
//== OTHER NON-PRIVATE CLASS METHODS ===========================================

//##############################################################################
//== CONSTUCTORS AND FACTORY METHODS ===========================================

    /***************************************************************************
     * Vytvoří test se zadaným názvem.
     *
     * @param name  Název konstruovaného testu
     */
    public RingTest(String name)
    {
        super(name);
    }



//== PREPARATION AND CLEANING THE FIXTURE ======================================

    /***************************************************************************
     * Inicializace předcházející spuštění každého testu a připravující tzv.
     * přípravek (fixture), což je sada objektů, s nimiž budou testy pracovat.
     */
    @Override
    protected void setUp()
    {
        CM = CanvasManager.getInstance();
        čtverec = Ring.čtverec(new Position(0,0));
        elko    = Ring.elko   (new Position(100, 100), NamedColor.BROWN);
//%A+ >141
        CM.add(čtverec, elko);
//%A-
        IO.inform("Okruhy připraveny");
    }


    /***************************************************************************
     * Úklid po testu - tato metoda se spustí po vykonání každého testu.
     */
    @Override
    protected void tearDown()
    {
    }


//== PRIVATE AND AUXILIARY CLASS METHODS =======================================
//== PRIVATE AND AUXILIARY INSTANCE METHODS ====================================
//%A+ >=135z

    /***************************************************************************
     * Zabalí zadaný posuvný objekt od okružního, výsledný okružní objekt
     * nasadí na zadané pole a vypustí jej; vrátí odkaz na přespříští pole.
     *
     * @param pole Pole, na něž bude nasazován vytvořený okružní objekt
     * @param ip   Posuvný objekt, který budeme balit do okružního
     * @return Následník následníka zadaného pole
     */
    private RoadField pomNasaď(RoadField pole, IMoveable ip)
    {
       Round okružní = new Round(ip);
       okružní.pokračujZ(pole);
       return pole.getDalší().getDalší();
    }

//%A-

    /***************************************************************************
     * Projede se se světlem po zadaném okruhu - verze používající
     * opakované volání funkce připravující budoucí hodnotu svého parametru.
     *
     * @param okruh Ring, který se bude objíždět
     */
    private void pomObjezd(Ring okruh)
    {
        RoadField počátek= okruh.getPočátek();
        Position    pozice = počátek.getPosition();
        Light    light = new Light(pozice.x, pozice.y);
        Mover přes   = new Mover(10);

        CM.add(light);
        počátek = pomPřesun(počátek, přes, light);
        počátek = pomPřesun(počátek, přes, light);
        počátek = pomPřesun(počátek, přes, light);
        //...     Předchozí příkaz je možno opakovat kolikrát bude potřeba
        počátek = pomPřesun(počátek, přes, light);
        počátek = pomPřesun(počátek, přes, light);
        počátek = pomPřesun(počátek, přes, light);
        počátek = pomPřesun(počátek, přes, light);
        počátek = pomPřesun(počátek, přes, light);
        počátek = pomPřesun(počátek, přes, light);
        počátek = pomPřesun(počátek, přes, light);
        počátek = pomPřesun(počátek, přes, light);
        počátek = pomPřesun(počátek, přes, light);

//        pomPřesun(počátek, přes, light, počátek);
    }

//%A+ >=135z

    /***************************************************************************
     * Projede se se světlem po zadaném okruhu - verze používající rekurzi.
     *
     * @param okruh Ring, který se bude objíždět
     */
    private void pomObjezdRek(Ring okruh)
    {
        RoadField počátek= okruh.getPočátek();
        Position    pozice = počátek.getPosition();
        Light    light = new Light(pozice.x, pozice.y);
        Mover přes   = new Mover(10);

        CM.add(light);

//Následjící příkaz vede na neukončené rekurzivní volání
//        pomPřesunRek(počátek, přes, light);

//Verze, při níž se objekt zastaví po dojetí na výchozí pole
        pomPřesunRek(počátek, přes, light, počátek);
    }

//%A-

    /***************************************************************************
     * Přesune pomocí zadaného přesouvače zadaný posuvný objekt
     * ze zadaného pole na jeho následníka a vrátí odkaz na tohoto následníka.
     *
     * @param pole      Pole, z nějž se vyjíždí
     * @param mover Mover, který objekt přesune
     * @param ip        Přesouvaný objekt
     * @return Následník výchozího pole = pole, na němž objekt skončí
     */
    private RoadField pomPřesun(RoadField pole, Mover mover,
                                IMoveable ip)
    {
        RoadField další  = pole.getDalší();
        Position    pozice = další.getPosition();
        mover.moveTo(pozice, ip);
        return další;
    }

//%A+ >=135z

    /***************************************************************************
     * Přesouvá pomocí zadaného přesouvače zadaný posuvný objekt
     * ze zadaného výchozího pole po posloupnosti zřetězencýh polí.
     * Po každém přesunu zavolá metoda sama sebe, čímž realizuje nekonečný
     * cycle, který směřuje k přeplnění zásobníku návratových adres.
     */
    private void pomPřesunRek(RoadField pole, Mover mover,
                              IMoveable ip)
    {
        RoadField další  = pole.getDalší();
        Position    pozice = další.getPosition();
        mover.moveTo(pozice, ip);
        pomPřesunRek(další, mover, ip);
    }


    /***************************************************************************
     * Přesouvá pomocí zadaného přesouvače zadaný posuvný objekt
     * ze zadaného výchozího pole po posloupnosti zřetězencýh polí.
     * Když dojede na zadaný počátečníá objekt, ohlásí objetí celého okruhu
     * a celou aplikaci ukončí.
     */
    private void pomPřesunRek(RoadField blok, Mover mover,
                              IMoveable ip, RoadField počátek)
    {
        RoadField další  = blok.getDalší();
        Position    pozice = další.getPosition();
        mover.moveTo(pozice, ip);
        IO.endIf(další.equals(počátek), "Okruh objet kolem dokola");
        pomPřesunRek(další, mover, ip, počátek);
    }

//%A-


//== EMBEDDED TYPES AND INNER CLASSES ==========================================
//== THE TESTS =================================================================
//
//     /***************************************************************************
//      *
//      */
//     public void testXXX()
//     {
//     }

    /***************************************************************************
     *
     */
    public void testElko()
    {
       pomObjezd(elko);
    }


    /***************************************************************************
     *
     */
    public void testČtverec()
    {
       pomObjezd(čtverec);
    }

//%A+ >=135z

    /***************************************************************************
     *
     */
    public void testElkoDek()
    {
       Round okružní = new Round(new Light());
       okružní.objížděj(elko);
    }


    /***************************************************************************
     *
     */
    public void testElkoRek()
    {
       pomObjezdRek(elko);
    }


    /***************************************************************************
     *
     */
    public void testČtverecRek()
    {
       pomObjezdRek(čtverec);
    }


    /***************************************************************************
     * Na oba okruhy postupně nasadí instance všech doposud definovaných
     * typů zabalené do okružních objektů a vypustí je na cestu po okruzích.
     * Umístí je tak, aby mezi nimi bylo vždy jedno pole volné.
     * Vedle stejně vzdálených instancí pohybujících se stejnou rychlostí přidá
     * ještě jednu s poloviční rychlostí a druhou s dvojnásobnou rychlostí.
     */
    public void testSkupinový()
    {
        RoadField pole = čtverec.getPočátek();
        int module = pole.getModule();

        pole = pomNasaď(pole, new Light());
        pole = pomNasaď(pole, new Triangle(0,0,50,50));

        pole  = elko.getPočátek();
        module = pole.getModule();

        pole = pomNasaď(pole, new Car(0, 0, 50));
        pole = pomNasaď(pole, new Ellipse(0, 0, 50, 50));
        pole = pomNasaď(pole, new TrafficLight(0, 0, 50/3));
        pole = pomNasaď(pole, new Rectangle(0, 0, 50, 50, NamedColor.GOLD));
        pole = pomNasaď(pole, new Arrow(0, 0, 50));
        pole = pomNasaď(pole, new Line(0, 0, module, module, NamedColor.WHITE));

        //Ještě jeden pomalý mnohotvar
        Multishape m = new Multishape("Trojobjekt", new Rectangle(),
                                    new Ellipse(), new Triangle());
        m.setSize(50);
        Round o = new Round(m);
        o.setSpeed(50);
        o.objížděj(elko);

        //A jeden rychlý text
        o = new Round(new Text(0, 0, NamedColor.YELLOW, "RYCHLIK"));
        o.setSpeed(200);
        o.objížděj(elko);

        IO.inform("Až se pokocháš, stiskni OK");
        Multimover.getInstance().zastavVše();
    }

//%A-
//%A+ >136

    /***************************************************************************
     * Test nasadí na small okruh šipku a na větší šipku a car.
     * Předvede, jak za pomoci dekorátoru {@link Rotable} objíždějí okruhy
     * přičemž jejich vzhle respektuje direction pohybu.
     */
    public void testPojízdný()
    {
        new Rotable(new Arrow()).goRound(čtverec);
        new Rotable(new TrafficLight()).continueFrom(
                čtverec.getPočátek().getDalší().getDalší());

        new Rotable(new Arrow()).goRound(elko);
        new Rotable(new Car()).continueFrom(
                elko.getPočátek().getDalší().getDalší());
        new Rotable(new TrafficLight()).continueFrom(
                elko.getPočátek().getDalší().getDalší().getDalší().getDalší());
    }

//%A-
//%A+ >141

    /***************************************************************************
     * Otestuje, jestli se okruhy umějí přizpůsobit nové velikosti modulu
     * a odpovídajícím způsobem upravit velikost a pozici jednotlivých políček.
     */
    public void testZměnaModulu()
    {
        Rectangle referenční = new Rectangle(50, 50, 100, 100,
                                            NamedColor.BLUE.translucent());
        CM.setSizeInFields(8, 7);
        CM.add(referenční);
        IO.inform("Zobrazen referenční Rectangle");
        for (int krok = 25;   krok < 150;   krok += 75) {
            CM.setStep(krok);
            čtverec.setModule(krok);
            elko   .setModule(krok);
            IO.inform("Krok upraven na " + krok);
        }
    }

//%A-
//%X+   Metoda připravená k vložení do testovacích tříd
     /** */
     public void testFixture() {}
//%X-
    }
//%%- ---- Start of the ovejumped text with closing of the envelope ----
////////////////////////////////////////////////////////////////////////////////
//== TESTING CLASSES AND METHODS ===============================================

    /***************************************************************************
     * Třída, jejíž instance má na starosti úklid mezi jednotlivými testy,
     * který není možno zakomponovat do metody {@code tearDown()},
     * dokud nebudou studenti umět programovat.
     */
    private static class TearDown implements Run.ITD
    {
        /** {@inheritDoc} */
        @Override
        public void cleanUp()
        {
//            Canvas.clearCanvas();
            CanvasManager.getInstance().removeAll();
        }
    }


    /***************************************************************************
     * Test method.
     */
    public static void test()
    {
        Run.tests(RingTest.class,
                new TearDown(),
//                "testFixture",
//                "testČtverec",
//                "testElko",
//                "testČtverecRek",
//                "testElkoRek",
//                "testElkoDek",
//                "testSkupinový",
//                "testPojízdný",
                "testZměnaModulu",
                "");
        System.exit(0);
    }
    /** @param args Parametry příkazového řádku - nepoužívané. */
    public static void main(String[] args)  {  test();  }
}
